package com.new4net.exe_stream.instruction.impl;

import com.new4net.exe_stream.instruction.BranchInstruction;
import com.new4net.exe_stream.instruction.Instruction;
import com.new4net.exe_stream.listener.InstructionListener;
import com.new4net.exe_stream.listener.impl.ExecutionLogListener;
import com.new4net.exe_stream.meta.ExecutionContext;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class ExecutionInstruction extends AbstractInstruction implements BranchInstruction<Instruction> {


    public ExecutionInstruction(String instructionName) {
        super(instructionName);




    }

    private List<Instruction> instructions = new ArrayList<>();


    private Instruction faultInstruction;



    public void addInstruction(Instruction instruction) {
        instructions.add(instruction);
    }

    public ExecutionInstruction addInstructionListener(InstructionListener instructionListener) {
        super.addInstructionListener(instructionListener);
        instructions.forEach(instruction -> instruction.addInstructionListener(instructionListener));
        return this;
    }


    public <R> R execute() {

        run();
        return executionContext.getReturnVal();
    }

    @SneakyThrows
    public void exeRetry() {
        boolean flag = false;

        for (Instruction instruction : instructions) {
            if (faultInstruction == instruction) {
                flag = true;
            }
            if (flag) {
                try {
                    instruction.retry();
                } catch (Throwable e) {
                    faultOneInstruction(e);

                }

            }


        }


    }



    protected void retryPrev() {
        super.retryPrev();
    }


    protected void prev() {

        executionContext.addParam("executionId", instructionId);
        executionContext.addParam("executionName", instructionName);
        super.prev();

    }

    protected void post() {
        retVal = instructionContext.getReturnVal();
        super.post();


    }

    @Override
    public void setExecutionContext(ExecutionContext executionContext) {
        super.setExecutionContext(executionContext);
        for (Instruction instruction : instructions) {
            instruction.setExecutionContext(executionContext);

        }
    }

    @Override
    protected void exe() {
        for (Instruction instruction : instructions) {
                instruction.run();


        }
    }

    @SneakyThrows
    private void faultOneInstruction(Throwable e) {
        faultInstruction = this;
        throw e;
    }

    @Override
    public List<Instruction> getChildren() {
        return instructions;
    }

    @Override
    public String getInstuctionType() {
        return "exe";
    }
}
